
//Convert Uint8Array to String
function uint8ArrayToString(arrayParam) {
    let arrayLen = arrayParam.length;
    let str = '';
    for (var idx = 0; idx < arrayLen; ++idx) {
        str += String.fromCharCode(arrayParam[idx]);
    }
    return str;
}

//Convert String to Uint8Array
function stringtoUint8Array(theStr) {
    var arr = [];
    var strLen = theStr.length;
    for (var idx = 0; idx < strLen; ++idx) {
        arr.push(theStr.charCodeAt(idx));
    }

    var tmpUint8Array = new Uint8Array(arr);
    return tmpUint8Array
}

async function pbkdf2Function(password, clientRandomValue) {

    // var randomValueLength = clientRandomValue.byteLength;
    var randomValueLength = 16;

    var clientRandomValueBinaryString = uint8ArrayToString(clientRandomValue)//Convert clientRandomValue to String

    //Generate Padding String ("SZTUBIGDATA"|| Padding || clientRandomValue)with length 200
    var shaString = "SZTUBIGDATA";
    var padLength = 200 - randomValueLength;
    shaString = shaString.padEnd(padLength, 'A');
    shaString = shaString + clientRandomValueBinaryString;
    console.log("shaString Length:" + shaString.length)

    const textEncoder = new TextEncoder();
    const shaMessage = textEncoder.encode(shaString);
    const hashBuffer = await crypto.subtle.digest('SHA-256', shaMessage)

    var salt = new Uint8Array(hashBuffer);

    const enPassword = await window.crypto.subtle.importKey(
        "raw",
        textEncoder.encode(password),
        {name: "PBKDF2"},
        false,
        ["deriveBits", "deriveKey"]
    );

    return window.crypto.subtle.deriveKey(
        {
            "name": "PBKDF2",
            "hash": "SHA-256",
            "salt": salt,
            "iterations": 100000
        },
        enPassword,
        {"name": "AES-GCM", "length": 256},
        true,
        ["encrypt", "decrypt"]
    );

}

async function encryptKey(keyArr, clientRandomValue, theKeyToEnc) {

    const params = {
        name: "AES-CBC",
        iv: clientRandomValue,
        length: 128
    };

    const aesKey = await crypto.subtle.importKey(
        "raw",
        keyArr.buffer,
        "AES-CBC",
        true,
        ["encrypt", "decrypt"]);

    const encryptedData = await crypto.subtle.encrypt(params, aesKey, theKeyToEnc);
    return encryptedData
}

async function decryptKey(keyArr, clientRandomValue, theKeyToDecrypt) {
    const params = {
        name: "AES-CBC",
        iv: clientRandomValue,
        length: 128
    };

    const aesKey = await crypto.subtle.importKey(
        "raw",
        keyArr.buffer,
        "AES-CBC",
        true,
        ["encrypt", "decrypt"]);

    const decryptedData = await crypto.subtle.decrypt(params, aesKey, theKeyToDecrypt);
    return decryptedData
}

function isEmail(emailStr) {
    var emailReg = /^\w+@[a-zA-Z0-9]{2,10}(?:\.[a-z]{2,4}){1,3}$/;
    return emailReg.test(emailStr);
}

//文件目录
function Catalogshow(obj) {

}

function readAsBinaryString(file) {

    return new Promise((resolve, reject) => {
        // var file = document.getElementById("file").files[0];
        var reader = new FileReader();
        //将文件以二进制形式读入页面
        reader.readAsBinaryString(file);
        reader.onload = (e) => {
            var num = e.target.result
            v1 = stringtoUint8Array(num);
            console.log(v1)
            //读取文件前128KB
            var v2 = new Uint8Array(128 * 1024)
            v2 = v1.subarray(0, 128 * 1024)
            console.log(v2)
            sessionStorage.setItem('v2', v2);
            resolve({
                v1,
                v2
            });
        };
    })
}

//upload file
async function UploadFile(obj) {
    var file = document.getElementById("file").files[0];
    //v1文件数据，v2文件前128KB数据
    let {
        v1 = new Uint8Array,
        v2 = new Uint8Array
    } = await readAsBinaryString(file)

    console.log(v1)
    console.log(v2)
    //对文件前128 KB数据利用SHA-256生成256位密钥
    const hashBuffer = await crypto.subtle.digest('SHA-256', v2)
    var sha256Key = new Uint8Array(hashBuffer);
    console.log("sha256Key:" + sha256Key);
    //
    // v3 = uint8ArrayToString(v2)
    // js 获取文件名，大小，ctime,mtime,atime
    fileSize = file.size;
    console.log("file size:" + fileSize);
    fileName = file.name;

    fileType = file.type;
    console.log(fileName)
    console.log(fileType)

    var Mtime = file.lastModifiedDate;
    console.log(Mtime)
    var Ctime = file.DateCreated;
    console.log(Ctime)
    var Atime = file.DateLastAccessed;
    console.log(Atime)


    //发送加密的密钥、文件名、ctime、mtime和atime
    let xhr = new XMLHttpRequest();
    xhr.open("post", url, true);//post data to registerhandle.jsp page

    let data = new FormData();
    data.append("key", key);
    data.append("fileName", fileName);
    data.append("ctime", ctime);
    data.append("mtime", mtime);
    data.append("atime", atime);

    xhr.send(data);
}

//上传成功响应
function uploadComplete(evt) {
    undefined
    //服务器接收完文件返回的结果
    alert("上传成功！");
}

//上传失败
function uploadFailed(evt) {
    undefined
    alert("上传失败！");
}

function newFolder() {
    var folderName = document.getElementById('text').value;
    let keyValue = new Uint8Array(2 ** 4);
    window.crypto.getRandomValues(keyValue);

}

//delete file
function DeleteFile(obj) {
    new File()
}

//download file
function DownloadFile(obj) {

}


/**
 *方法名：folderSingleCreate
 *作用：创建一级文件夹
 **/
function folderSingleCreate() {

    var path = document.getElementById('folder_single').value;

    if (!runObj.FolderExists(path)) {
        runObj.CreateFolder(path);
        alert('文件夹创建成功。');
    } else {
        alert('文件夹已存在。');

    }


}

function reset(){
    document.getElementById('email').value='';
    document.getElementById('password').value='';
    document.getElementById('passwordAgain').value='';
}

async function register() {
    console.log("register function called")

    var registerForm = document.getElementById('registerForm');

    let email = document.getElementById('email').value;
    console.log("email:" + email)
    let password = document.getElementById('password').value
    let passwordAgain = document.getElementById('passwordAgain').value

    if (!isEmail(email)) {
        alert("请输入正确的邮箱")
        reset();
        return
    }

    if (password != passwordAgain) {
        alert("两次密码不一致，请重新输入")
        reset();
        return
    }

    let clientRandomValue = new Uint8Array(2 ** 4);
    let masterKey = new Uint8Array(2 ** 4);
    window.crypto.getRandomValues(clientRandomValue);
    window.crypto.getRandomValues(masterKey);

    console.log("masterKey:" + masterKey);
    console.log("clientRandomValue:" + clientRandomValue);
    let pbkdf2Key = await pbkdf2Function(password, clientRandomValue);
    const rawKey = await crypto.subtle.exportKey('raw', pbkdf2Key);
    const rawKeyArray = new Uint8Array(rawKey)

    const left128Bits = rawKeyArray.subarray(0, 16);
    const right128Bits = rawKeyArray.slice(16, rawKeyArray.length);

    console.log("pbkdf2RawKey:" + rawKeyArray);
    console.log("left128Bits Length:" + left128Bits.length + " Value:" + left128Bits);
    console.log("right128Bits Length:" + right128Bits.length + " Value:" + right128Bits);

    const hashBuffer = await crypto.subtle.digest('SHA-256', right128Bits)
    var sha256VerifyKey = new Uint8Array(hashBuffer);

    console.log("masterKey:" + masterKey)
    var encryptedMasterKeyHashValue = await encryptKey(left128Bits, clientRandomValue, masterKey)
    var encryptedMasterKey = new Uint8Array(encryptedMasterKeyHashValue)
    console.log("encryptedMasterKey:" + encryptedMasterKey)

    var deKeyBuffer = await decryptKey(left128Bits, clientRandomValue, encryptedMasterKey)
    var decryptedMasterKey = new Uint8Array(deKeyBuffer)
    console.log("decryptedMasterKey:" + decryptedMasterKey)

    //Avoid password stole by server before interaction
    document.getElementById('password').value = "OverwritePassword";
    document.getElementById('passwordAgain').value = "OverwritePassword";

    console.log("sha256VerifyKey:" + sha256VerifyKey);
    /*What mainly to post: encryptedMasterKey, clientRandomValue, email, sha256VerifyKey
      1. Arraybuffer of Encrypted Master Key: 128 bit;
      2. Arraybuffer of Client Random Value: 128 bit;
      3. String of Email Address;
      3. Arraybuffer of hashed value with sha-256 to the right128Bits;
    */

    //start to post data with XMLHttpRequest()
    // let xhr = new XMLHttpRequest();
    // xhr.open("post", "", true);//post data to registerhandle.jsp page

    let data = {
        "email":email,
        "clientRandomValue": Array.from(clientRandomValue),
        "encryptedMasterKey":Array.from(encryptedMasterKey),
        "sha256VerifyKey":Array.from(sha256VerifyKey)
    };
    // clientRandomValue =  Array.from(clientRandomValue)
    // console.log(JSON.stringify(clientRandomValue));
    // console.log(JSON.stringify(data))

    $.ajax({
        url: "/register",
        method: "post",
        async: true,
        data: JSON.stringify(data),
        contentType: "application/json;charset=UTF-8",
        dataType: "json",
        success:function (data){
            alert(data)
            let tips = $("#tips");
            tips.innerText = data.message;
            tips.style.display='inline';
            tips.style.color='red';
        }
    })
}

async function login() {
    var loginForm = $("#loginForm");

    let email = $("#email").value
    // let password = loginForm.elements['password'].value

    sessionStorage.setItem('key', $("password"));

    if (!isEmail(email)) {
        alert("请输入正确的邮箱")
        reset();
        return;
    }

    // 检查用户是否存在
    let xhr = new XMLHttpRequest();
    xhr.open("post", "loginForm", true);//post data to loginhandle.jsp page

    let data = new FormData();
    data.append("email", email);
    xhr.send(data);


    //get clientRandomValue from registerhandle.jsp page
    let xhr1 = new XMLHttpRequest();
    xhr1.responseType = 'text';
    xhr1.open('get', "loginhandle", true);

    let clientRandomValue = new Uint8Array(2 ** 4);
    xhr1.onreadystatechange = function () {
        if (xhr1.readyState === 4) {
            if (xhr1.status === 200) {
                clientRandomValue = xhr1.responseText
            } else {
                console.error(xhr1.statusText)
            }
        }
    }

    xhr1.onerror = function () {
        alert("用户不存在，请注册")
        loginForm.reset()
        console.log('error')
    }

    xhr1.onreadystatechange = function () {
        if (xhr1.readyState === 4) {
            if (xhr1.status === 200) {

                console.log(xhr1.responseText)
            } else {
                console.error(xhr1.statusText)
            }
        }
    }

    xhr1.onerror = function () {
        console.log('error')
    }

    xhr1.send()
    //测试
    //let clientRandomValue = new Uint8Array(2 ** 4);
    //clientRandomValue=[8,4,225,158,168,186,201,170,95,5,27,187,255,119,79,129]
    //
    console.log("clientRandomValue:" + clientRandomValue);

    let password = sessionStorage.getItem('key');
    console.log("password:" + password);
    let pbkdf2Key = await pbkdf2Function(password, clientRandomValue);
    const rawKey = await crypto.subtle.exportKey('raw', pbkdf2Key);
    const rawKeyArray = new Uint8Array(rawKey)

    const left128Bits = rawKeyArray.subarray(0, 16);
    const right128Bits = rawKeyArray.slice(16, rawKeyArray.length);

    console.log("pbkdf2RawKey:" + rawKeyArray);
    console.log("left128Bits Length:" + left128Bits.length + " Value:" + left128Bits);
    console.log("right128Bits Length:" + right128Bits.length + " Value:" + right128Bits);

    const hashBuffer = await crypto.subtle.digest('SHA-256', right128Bits)
    var sha256VerifyKey = new Uint8Array(hashBuffer);
    console.log("sha256VerifyKey:" + sha256VerifyKey);
    //发后128hash值
    let xhr2 = new XMLHttpRequest();
    xhr2.open("post", "loginhandle", true);
    //post data to loginhandle.jsp page

    let data1 = new FormData();
    data1.append("sha256VerifyKey", sha256VerifyKey);

    xhr2.send(data1);
    //接收是否正确
    let xhr3 = new XMLHttpRequest();
    xhr3.open("get", "loginhandle", true);
    //post data to loginhandle.jsp page

    xhr2.send();
    if (xhr1.responseText == 0) {
        alert("密码错误，请输入正确的密码")
        loginForm.reset();
        return;
    }


}

